package br.ufmg.dcc.vod.remoteworkers.async;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import br.ufmg.dcc.vod.remoteworkers.Command;
import br.ufmg.dcc.vod.remoteworkers.CommandError;

public class QueueBasedAsyncRemoteProcessor extends AbstractQueueBasedAsyncEntity<AsyncCommandRequest<?, ?>> implements AsyncCommandProcessor {

	private static final long serialVersionUID = 1L;

	private final List<RMIExceptionListener> listeners;
	
	public QueueBasedAsyncRemoteProcessor(int port) throws RemoteException {
		super(port);
		this.listeners = Collections.synchronizedList(new ArrayList<RMIExceptionListener>());
	}

	public void addListener(RMIExceptionListener listener) {
		this.listeners.add(listener);
	}
	
	public void removeListener(RMIExceptionListener listener) {
		this.listeners.remove(listener);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void receive(AsyncCommandRequest<?, ?> poll) {
		Command command = poll.getCommand();
		CommandInterested interested = poll.getCommandResponseInterested();
		String location = poll.getCommandResponseInterestedObjectLocation();
		
		Object id = null;
		Object process = null;
		try {
			process = command.process();
			id = command.getID();
			interested.commandResponse(id, process);
		} catch (RemoteException re) {
			synchronized(listeners) {
				for (RMIExceptionListener listener : listeners) {
					listener.rmiExceptionOcurredOnCmdResponse(this, interested, location, id, process);
				}
			}
		} catch (Exception e) {
			CommandError error = new CommandError(e);
			id = command.getID();
			try {
				interested.commandError(id, error);
			} catch (RemoteException re) {
				synchronized(listeners) {
					for (RMIExceptionListener listener : listeners) {
						listener.rmiExceptionOcurredOnCmdError(this, interested, location, id, error);
					}
				}
			}
		}
	}

	@Override
	public <T, I> void process(AsyncCommandRequest<T, I> request) throws RemoteException {
		queue(request);
	}
}